package com.blue.http.message;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;

import com.blue.core.dict.HttpMethod;
import com.blue.core.util.BeanUtil;
import com.blue.core.util.JsonUtil;
import com.blue.core.util.UrlUtil;
import com.blue.validation.ValidationUtil;

import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.QueryStringDecoder;
import io.netty.handler.codec.http.cookie.Cookie;
import io.netty.handler.codec.http.cookie.ServerCookieDecoder;
import io.netty.util.CharsetUtil;

/**
 * HTTP 请求参数默认实现类
 * 
 * @author zhengj
 * @since 1.0 2017年3月1日
 */
public class DefaultHttpRequest implements HttpRequest
{
	private static Logger logger = LoggerFactory.getLogger(DefaultHttpRequest.class);

	private String path; // 应用根路径
	private String url; // http 路径
	private Map<String, String> queryMap = new HashMap<>(); // URL参数
	private String queryString; // URL参数
	private HttpMethod httpMethod; // http 请求方法
	private String ip; // 请求IP地址
	private long start; // 开始时间戳
	private long contentLength; // 内容长度
	private HttpHeaders headers; // Http请求头

	private String content; // POST内容
	private Map<String, String> postMap = new HashMap<>(); // POST参数
	private Map<String, UploadFile> fileMap = new HashMap<>(); // 上传文件

	private Map<String, String> cookieMap = new HashMap<>(); // Cookie

	public DefaultHttpRequest(HttpMethod httpMethod, String ip)
	{
		this.httpMethod = httpMethod;
		this.ip = ip;
		this.start = System.currentTimeMillis();
	}

	/**
	 * 解析Uri
	 * 
	 * @param uri
	 */
	public void parseUri(String uri, String path)
	{
		this.path = path;
		QueryStringDecoder decoder = new QueryStringDecoder(uri, CharsetUtil.UTF_8, true);
		url = UrlUtil.getRealPath(path, decoder.path());

		List<String> queryList = new ArrayList<>();
		if (decoder.parameters() != null && !decoder.parameters().isEmpty())
		{
			for (Map.Entry<String, List<String>> entry : decoder.parameters().entrySet())
			{
				String value = null;
				if (entry.getValue() != null && !entry.getValue().isEmpty())
				{
					if (entry.getValue().size() == 1)
					{
						value = entry.getValue().get(0);
					}
					else
					{
						value = StringUtils.join(entry.getValue(), ",");
					}
					try
					{
						value = URLDecoder.decode(value, "UTF-8");
					}
					catch (UnsupportedEncodingException e)
					{
						e.printStackTrace();
					}
				}
				queryMap.put(entry.getKey(), value);
				queryList.add(entry.getKey() + "=" + value);
			}
		}
		queryString = StringUtils.join(queryList, "&");
	}


	public void parseHeaders(HttpHeaders headers)
	{
		if (headers == null)
			return;

		this.headers = headers;

		String cookie = headers.get(HttpHeaderNames.COOKIE);
		if (cookie != null && !cookie.isEmpty())
		{
			Set<Cookie> set = ServerCookieDecoder.STRICT.decode(cookie);
			if (set != null && !set.isEmpty())
			{
				for (Cookie c : set)
				{
					cookieMap.put(c.name(), c.value());
				}
			}
		}
	}

	public void setContent(String content)
	{
		this.content = content;
	}

	@Override
	public <T> T getQueryObject(Class<T> clazz, Class<?>... groups)
	{
		T obj = BeanUtil.createBean(clazz, queryMap);
		if (obj != null && groups.length > 0)
		{
			ValidationUtil.valid(obj, groups);
		}
		return obj;
	}

	@Override
	public String getUrl()
	{
		return url;
	}

	@Override
	public String getPath()
	{
		return path;
	}

	@Override
	public String getQueryString()
	{
		return queryString;
	}

	@Override
	public String getQueryString(String name)
	{
		Assert.hasText(name, "属性名称不能为空");
		return queryMap.get(name);
	}

	@Override
	public int getQueryInt(String name, int defaultVal)
	{
		Assert.hasText(name, "属性名称不能为空");
		String str = queryMap.get(name);
		if (str == null || str.isEmpty())
			return defaultVal;
		
		str = str.trim();
		if (str.isEmpty())
			return defaultVal;
		
		try
		{
			defaultVal = Integer.parseInt(str);
		}
		catch (NumberFormatException e)
		{
			logger.warn("无法转换成整数：{}，用默认值：{}", str, defaultVal);
		}
		return defaultVal;
	}

	@Override
	public double getQueryDouble(String name, double defaultVal)
	{
		Assert.hasText(name, "属性名称不能为空");
		String str = queryMap.get(name);
		if (str == null || str.isEmpty())
			return defaultVal;
		
		str = str.trim();
		if (str.isEmpty())
			return defaultVal;
		
		try
		{
			defaultVal = Double.parseDouble(str);
		}
		catch (NumberFormatException e)
		{
			logger.warn("无法转换成浮点数：{}，用默认值：{}", str, defaultVal);
		}
		return defaultVal;
	}

	@Override
	public Map<String, String> getQueryStringMap()
	{
		return queryMap;
	}

	@Override
	public String getContent()
	{
		return content;
	}
	
	@Override
	public <T> T getContentJson(Class<T> clazz, Class<?>... groups)
	{
		Assert.notNull(clazz, "类型不能为空");
		if (content == null || content.isEmpty())
			return null;
		
		T obj = JsonUtil.decode(content, clazz);
		if (obj != null)
		{
			ValidationUtil.valid(obj, groups);
		}
		return obj;
	}
	
	@Override
	public Map<String, String> getPostMap()
	{
		return postMap;
	}
	
	@Override
	public String getPost(String name)
	{
		Assert.hasText(name, "属性名称不能为空");
		return postMap.get(name);
	}

	@Override
	public int getPostInt(String name, int defaultVal)
	{
		Assert.hasText(name, "属性名称不能为空");
		String str = postMap.get(name);
		if (str == null || str.isEmpty())
			return defaultVal;

		str = str.trim();
		if (str.isEmpty())
			return defaultVal;

		try
		{
			defaultVal = Integer.parseInt(str);
		}
		catch (NumberFormatException e)
		{
			logger.warn("无法转换成整数：{}，用默认值：{}", str, defaultVal);
		}
		return defaultVal;
	}

	@Override
	public double getPostDouble(String name, double defaultVal)
	{
		Assert.hasText(name, "属性名称不能为空");
		String str = postMap.get(name);
		if (str == null || str.isEmpty())
			return defaultVal;

		str = str.trim();
		if (str.isEmpty())
			return defaultVal;

		try
		{
			defaultVal = Double.parseDouble(str);
		}
		catch (NumberFormatException e)
		{
			logger.warn("无法转换成浮点数：{}，用默认值：{}", str, defaultVal);
		}
		return defaultVal;
	}

	@Override
	public <T> T getPostObject(Class<T> clazz, Class<?>... groups)
	{
		T obj = BeanUtil.createBean(clazz, postMap);
		if (obj != null && groups.length > 0)
		{
			ValidationUtil.valid(obj, groups);
		}
		return obj;
	}

	@Override
	public Map<String, UploadFile> getFileMap()
	{
		return fileMap;
	}

	@Override
	public UploadFile getFile(String name)
	{
		return fileMap.get(name);
	}

	@Override
	public UploadFile getFile()
	{
		Iterator<UploadFile> iterator = fileMap.values().iterator();
		if (iterator.hasNext())
			return iterator.next();
		
		return null;
	}

	public void setContentLength(long contentLength)
	{
		this.contentLength = contentLength;
	}

	@Override
	public Map<String, String> getCookieMap()
	{
		return cookieMap;
	}

	@Override
	public String getCookie(String name)
	{
		return cookieMap.get(name);
	}

	@Override
	public HttpMethod getHttpMethod()
	{
		return httpMethod;
	}

	@Override
	public String getIp()
	{
		return ip;
	}

	@Override
	public long getStart()
	{
		return start;
	}

	@Override
	public long getContentLength()
	{
		return contentLength;
	}

	@Override
	public boolean isWechat()
	{
		String agent = headers.get(HttpHeaderNames.USER_AGENT);
		logger.info("User-Agent: {}", agent);
		return agent.indexOf("MicroMessenger") != -1;
	}

}
